package org.example.chat.aop;

import lombok.extern.slf4j.Slf4j;
import org.aspectj.lang.JoinPoint;
import org.aspectj.lang.annotation.AfterReturning;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Before;
import org.aspectj.lang.annotation.Pointcut;
import org.aspectj.lang.reflect.MethodSignature;
import org.example.chat.config.ServerConfigProperties;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;

@Component
@Aspect
@Slf4j
public class LogAspect {

    @Autowired
    private ServerConfigProperties serverConfigProperties;

    /** 存放调用方法执行前的时间戳 */
    private static final ThreadLocal<Long> beforeMethodExecuteTime = new ThreadLocal<>();

    @Pointcut(value = "@annotation(org.example.chat.aop.annotation.Log)")
    public void logPointcut() {

    }

    @Before(value = "logPointcut()")
    public void beforeMethodInvoke(JoinPoint joinPoint) {
        // 0. 判断是否开启日志打印
        if (!serverConfigProperties.isPrintMethodLog()) {
            return;
        }
        // 1. 获取执行方法的全名
        MethodSignature signature = (MethodSignature) joinPoint.getSignature();
        String simpleMethodName = signature.getName();
        String className = signature.getDeclaringTypeName();
        String methodName = className + "." + simpleMethodName + "()";
        // 2. 打印日志
        log.info("方法【{}】>>>>>>>>> 开始执行", methodName);
        // 3. 记录方法开始执行时的时间戳
        beforeMethodExecuteTime.set(System.currentTimeMillis());
    }

    @AfterReturning(value = "logPointcut()")
    public void afterMethodInvoke(JoinPoint joinPoint) {
        // 0. 判断是否开启日志打印
        if (!serverConfigProperties.isPrintMethodLog()) {
            return;
        }
        // 1.获取执行方法的全名
        MethodSignature signature = (MethodSignature) joinPoint.getSignature();
        String simpleMethodName = signature.getName();
        String className = signature.getDeclaringTypeName();
        String methodName = className + "." + simpleMethodName + "()";
        // 2. 计算方法执行时间
        long executeTime = System.currentTimeMillis() - beforeMethodExecuteTime.get();
        // 释放threadlocal防止内存泄漏
        beforeMethodExecuteTime.remove();
        // 3. 打印日志
        log.info("方法【{}】>>>>>>>>> 执行结束，耗时 >>>>> {}ms", methodName, executeTime);
    }
}
